Skip to content

Lec1

1. Preparation:Operator system interfaces

book-riscv-rev3 Chapter1

1.1 Processes and memory

  • An xv6 process consists of user-space memory (instructions, data, and stack) and per-process state private to the kernel.
  • A process may create a new process using the fork system call.

  • If exec succeeds then the child will execute instructions from echo instead of runcmd. At some point echo will call exit, which will cause the parent to return from wait in main (user/sh.c:146).
  • why fork and exec are not combined in a single call; we will see later that the shell exploits the separation in its implementation of I/O redirection. To avoid the wastefulness of creating a duplicate process and then immediately replacing it (with exec), operating kernels optimize the implementation of fork for this use case by using virtual memory techniques such as copy-on-write (see Section 4.6).
  • Xv6 allocates most user-space memory implicitly.

1.2 I/O and File descriptors

  • A file descriptor is a small integer representing a kernel-managed object that a process may read from or write to.
  • the file descriptor interface abstracts away the differences between files, pipes, and devices, making them all look like streams of bytes. We’ll refer to input and output as I/O.
  • By convention, a process reads from file descriptor 0 (standard input), writes output to file descriptor 1 (standard output), and writes error messages to file descriptor 2 (standard error).
    • the shell exploits the convention to implement I/O redirection and pipelines. The shell ensures that it always has three file descriptors open (user/sh.c:152), which are by default file descriptors for the console.
  • The read and write system calls read bytes from and write bytes to open files named by file descriptors.
  • The use of file descriptors and the convention that file descriptor 0 is input and file descriptor 1 is output allows a simple implementation of cat.
  • A newly allocated file descriptor is always the lowest-numbered unused descriptor of the current process.
  • The system call exec replaces the calling process’s memory but preserves its file table. This behavior allows the shell to implement I/O redirection by forking, re-opening chosen file descriptors in the child, and then calling exec to run the new program.
  • The parent process’s file descriptors are not changed by this sequence, since it modifies only the child’s descriptors.
  • The second argument to open consists of a set of flags, expressed as bits, that control what open does.
    • like:open("input.txt", O_RDONLY)
  • Now it should be clear why it is helpful that fork and exec are separate calls: between the two, the shell has a chance to redirect the child’s I/O without disturbing the I/O setup of the main shell.
  • Although fork copies the file descriptor table, each underlying file offset is shared between parent and child.
  • The dup system call duplicates an existing file descriptor, returning a new one that refers to the same underlying I/O object. Both file descriptors share an offset, just as the file descriptors duplicated by fork do.
  • a process writing to file descriptor 1 may be writing to a file, to a device like the console, or to a pipe.

1.3 Pipe

  • A pipe is a small kernel buffer exposed to processes as a pair of file descriptors, one for reading and one for writing. Writing data to one end of the pipe makes that data available for reading from the other end of the pipe. Pipes provide a way for processes to communicate.

  • If no data is available, a read on a pipe waits for either data to be written or for all file descriptors referring to the write end to be closed.
  • The fact that read blocks until it is impossible for new data to arrive is one reason that it’s important for the child to close the write end of the pipe before executing wc above
  • (e.g., a | b | c) the shell may create a tree of processes.
  • Pipes may seem no more powerful than temporary files: the pipeline
    • echo hello world | wc could be implemented without pipes as `echo hello world >/tmp/xyz; wc